package tum0r.server.problem.web.sql_injection.blind;

import tum0r.generate_code.database.DB;
import tum0r.model.ProblemInfoItem;
import tum0r.model.ProblemLevel;
import tum0r.server.problem.ProblemBase;
import tum0r.utils.extension.StringExtension;
import tum0r.webengine.annotation.Param;
import tum0r.webengine.annotation.Server;
import tum0r.webengine.model.server.ErrorMessage;
import tum0r.webengine.utils.server.action.Action;

/**
 * 工程: Security<br>
 * 包: tum0r.server.problem.web.sql_injection.blind.bool<br>
 * 创建者: tum0r<br>
 * 创建时间: 2021/3/24 21:02<br>
 * <br>
 */
@Server(Mapping = "/security/problem/web/sql_injection/blind/bool")
public class Bool extends ProblemBase {
    public Bool() {
        information.ProblemTitle = "有趣的SQL注入——布尔盲注";
        information.ProblemID = 6;
        information.Creator = "tum0r";
        information.ProblemLevel = ProblemLevel.FUNNY;
        information.CreateTime = "2020/03/24";

        ProblemInfoItem problem = new ProblemInfoItem("problem", null);
        problem.addParameter("username", "String");
        problem.addParameter("password", "String");
        information.ProblemInfo.add(problem);
    }

    @Override
    public void description(Action<String> action) {
        action.callBack("""
                账号:admin
                密码:admin
                猜猜看flag被藏在哪？
                """);
    }

    @Override
    public void tips(Action<String> action) {
        action.callBack("String sql = \"SELECT EXISTS(SELECT 1 FROM `user` WHERE UserName = '\" + username + \"' AND `Password` = '\" + password + \"') AS success\";");
    }

    @Override
    public void writeUp(Action<String> action) {
        String result = """
                0、用户登录，所以为字符型注入
                                
                1、肯定用了条件判断SQL语句验证用户名和密码是否正确，所以写脚本盲注
                                
                3、根据 LENGTH(DATABASE()) 拿到数据库名称的长度
                                
                4、根据 SUBSTR(DATABASE(),1,1) = 's' 这样的语句猜解数据库名
                                
                5、根据 LENGTH((SELECT GROUP_CONCAT(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'security')) 拿到表名的总长度
                                
                6、根据 SUBSTR((SELECT GROUP_CONCAT(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'security'),1,1) = 'f' 这样的语句猜解出所有表
                                
                7、类似上面的思路拿到f1ag表中的字段名
                                
                8、类似上面的思路根据ProblemID拿到flag
                """;
        action.callBack(result);
    }

    public void problem(@Param("username") String username, @Param("password") String password, Action<String> action) throws ErrorMessage {
        action.check(!StringExtension.isNotNullOrEmpty(username) || !StringExtension.isNotNullOrEmpty(password), "用户名或密码不能为空");

        String sql = "SELECT EXISTS(SELECT 1 FROM `user` WHERE UserName = '" + username + "' AND `Password` = '" + password + "')";
        boolean result = false;
        try {
            result = DB._Write._DAO.selectValueUnsafe(sql, boolean.class);
        } catch (Exception ignored) {
        }

        action.callBack(result ? "Login Success" : "Login Fail");
    }
}
